package com.bestcem.xm.txtanls.grpc.service;

import cn.hutool.core.collection.CollUtil;
import com.bestcem.xm.common.core.domain.web.RpcStatusResult;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.txtanls.grpc.convert.ChartConvert;
import com.bestcem.xm.txtanls.grpc.service.param.PageParam;
import com.bestcem.xm.txtanls.grpc.service.param.record.DownloadRecordParam;
import com.bestcem.xm.txtanls.grpc.service.param.record.ListRecordParam;
import com.bestcem.xm.txtanls.grpc.service.param.record.QueryConditionParam;
import com.bestcem.xm.txtanls.grpc.service.param.record.RecordTopicRelationParam;
import com.bestcem.xm.txtanls.grpc.v1.common.BaseModel;
import com.bestcem.xm.txtanls.grpc.v1.enums.RecordSentimentEnum;
import com.bestcem.xm.txtanls.grpc.v1.enums.RecordStatusEnum;
import com.bestcem.xm.txtanls.grpc.v1.services.*;
import com.bestcem.xm.txtanls.service.RecordService;
import com.bestcem.xm.txtanls.service.dto.chart.PeriodTimeDTO;
import com.bestcem.xm.txtanls.service.dto.chart.TimeRangeDTO;
import com.bestcem.xm.txtanls.service.dto.record.*;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import static com.bestcem.xm.common.core.constant.Constants.DEFAULT_ARRAY_SIZE;

/**
 * 原话记录GRPC服务实现类
 *
 * @author XiaoYunSong
 * @version 1.0
 * @date 2021/5/14 11:22
 */
@Slf4j
@GrpcService
public class RecordGrpcService extends RecordServiceGrpc.RecordServiceImplBase {

    @Resource
    private RecordService recordService;

    /**
     * 获取当前文本分析项目已有原话记录中的最大时间
     *
     * @param request          request
     * @param responseObserver response
     * @author liheng
     * @date 2021/5/14 11:23
     */
    @Override
    public void getRecordMaxTime(GetRecordMaxTimeRequest request, StreamObserver<GetRecordMaxTimeResponse> responseObserver) {
        String projectId = request.getProjectId();
        GetRecordMaxTimeResponse.Builder builder = GetRecordMaxTimeResponse.newBuilder();
        if (StringUtils.isBlank(projectId) || !ObjectId.isValid(projectId)) {
            builder.setStatus(RpcStatusResult.error("projectId错误"));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<LocalDateTime> recordMaxTime = recordService.getRecordMaxTime(projectId);
        if (recordMaxTime.isSuccess()) {
            LocalDateTime date = recordMaxTime.getData();
            builder.setStatus(RpcStatusResult.success());
            builder.setMaxTime(DateUtil.getTimestamp(date));
        } else {
            builder.setStatus(RpcStatusResult.error(recordMaxTime.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 根据输入词查询原话记录
     *
     * @param request          request
     * @param responseObserver response
     * @author liheng
     * @date 2021/5/14 11:25
     */
    @Override
    public void listRecord(ListRecordRequest request, StreamObserver<ListRecordResponse> responseObserver) {
        ListRecordParam listRecordParam = new ListRecordParam(PageParam.infoToParam(request.getPage()).setRecordDefaultSize(),
                ChartConvert.timeRangeToTimeRangeDTO(request.getTimeRange()), queryParamToParam(request.getQueryParam()));
        ListRecordResponse.Builder builder = ListRecordResponse.newBuilder();
        TimeRangeDTO timeRangeDTO = listRecordParam.getTimeRangeDTO();
        PeriodTimeDTO periodTime = timeRangeDTO.getPeriodTime();
        if (Objects.nonNull(periodTime)) {
            LocalDateTime startTime = periodTime.getStartTime();
            LocalDateTime endTime = periodTime.getEndTime();
            if (Objects.nonNull(startTime) && Objects.nonNull(endTime) && startTime.isAfter(endTime)) {
                builder.setStatus(RpcStatusResult.error("时间区间开始时间不能大于结束时间"));
                responseObserver.onNext(builder.build());
                responseObserver.onCompleted();
                return;
            }
        }
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(listRecordParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<ListRecordDTO> serviceResult = recordService.listRecord(listRecordParam);
        if (serviceResult.isSuccess()) {
            ListRecordDTO data = serviceResult.getData();
            builder.setStatus(RpcStatusResult.success());
            builder.setPage(PageParam.convertToPage(data.getPageParam()));
            builder.setTotal(data.getPageResult().getTotal());
            builder.addAllRecords(listRecordTransfer(data.getPageResult().getData()));
        } else {
            builder.setStatus(RpcStatusResult.error(serviceResult.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 导出原话记录
     *
     * @param request          request
     * @param responseObserver response
     */
    @Override
    public void downloadRecord(DownloadRecordRequest request, StreamObserver<DownloadRecordResponse> responseObserver) {
        DownloadRecordParam downloadRecordParam =
                new DownloadRecordParam(ChartConvert.timeRangeToTimeRangeDTO(request.getTimeRange()),
                        this.queryParamToParam(request.getQueryParam()));
        DownloadRecordResponse.Builder builder = DownloadRecordResponse.newBuilder();
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(downloadRecordParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<DownloadRecordDTO> result = recordService.downloadRecord(downloadRecordParam);
        if (result.isSuccess()) {
            DownloadRecordDTO data = result.getData();
            builder.setStatus(RpcStatusResult.success());
            if (StringUtils.isNotBlank(data.getFileName())) {
                builder.setFileName(data.getFileName());
            }
            if (StringUtils.isNotBlank(data.getUrl())) {
                builder.setFileUrl(data.getUrl());
            }
            if (StringUtils.isNotBlank(data.getFileType())) {
                builder.setFileType(data.getFileType());
            }
            if (Objects.nonNull(data.getFileSize())) {
                builder.setSize(data.getFileSize());
            }
        } else {
            builder.setStatus(RpcStatusResult.error(result.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }

    /**
     * 已关联话题原话记录和未关联话题原话记录的数量 (话题管理页面左上角)
     *
     * @param request          request
     * @param responseObserver response
     */
    @Override
    public void getRecordTopicRelation(GetRecordTopicRelationRequest request, StreamObserver<GetRecordTopicRelationResponse> responseObserver) {
        RecordTopicRelationParam recordTopicRelationParam =
                new RecordTopicRelationParam(request.getProjectId(),
                        request.getFieldId(),
                        ChartConvert.timeRangeToTimeRangeDTO(request.getTimeRange()));
        GetRecordTopicRelationResponse.Builder builder = GetRecordTopicRelationResponse.newBuilder();
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(recordTopicRelationParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            builder.setStatus(RpcStatusResult.error(violation.getMessage()));
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
            return;
        }
        ServiceResult<RecordTopicRelationDTO> recordTopicRelation = recordService.getRecordTopicRelation(recordTopicRelationParam);
        if (recordTopicRelation.isSuccess()) {
            RecordTopicRelationDTO data = recordTopicRelation.getData();
            builder.setStatus(RpcStatusResult.success());
            builder.setAssociatedCount(data.getAssociatedCount());
            builder.setNotAssociatedCount(data.getNotAssociatedCount());
        } else {
            builder.setStatus(RpcStatusResult.error(recordTopicRelation.getMsg()));
        }
        responseObserver.onNext(builder.build());
        responseObserver.onCompleted();
        return;
    }


    private QueryConditionParam queryParamToParam(QueryParam param) {
        QueryConditionParam queryConditionParam = new QueryConditionParam();
        queryConditionParam.setProjectId(param.getProjectId());
        queryConditionParam.setWord(param.getWord());
        queryConditionParam.setEmotion(param.getEmotion().getNumber());
        queryConditionParam.setFieldId(param.getFieldId());
        queryConditionParam.setTopicId(param.getTopicId());

        return queryConditionParam;
    }

    private List<RecordInfo> listRecordTransfer(List<RecordDetailDTO> dataList) {
        List<RecordInfo> recordInfos = new ArrayList<>(dataList.size());
        for (int i = 0; i < dataList.size(); i++) {
            RecordDetailDTO recordDetailDTO = dataList.get(i);
            RecordInfo recordInfo = dtoToResponse(recordDetailDTO);
            recordInfos.add(recordInfo);
        }
        return recordInfos;
    }

    private RecordInfo dtoToResponse(RecordDetailDTO data) {
        RecordInfo.Builder builder = RecordInfo.newBuilder();
        if (StringUtils.isNotBlank(data.getId())) {
            builder.setId(data.getId());
        }
        if (StringUtils.isNotBlank(data.getContent())) {
            builder.setContent(data.getContent());
        }
        if (StringUtils.isNotBlank(data.getProjectId())) {
            builder.setProjectId(data.getProjectId());
        }
        if (Objects.nonNull(data.getSentimentScore())) {
            builder.setSentimentScore(data.getSentimentScore());
        }
        if (StringUtils.isNotBlank(data.getWorktableId())) {
            builder.setWorktableId(data.getWorktableId());
        }
        if (StringUtils.isNotBlank(data.getWorktableName())) {
            builder.setWorktableName(data.getWorktableName());
        }
        if (StringUtils.isNotBlank(data.getCollectionId())) {
            builder.setCollectionId(data.getCollectionId());
        }
        if (Objects.nonNull(data.getSentiment())) {
            builder.setSentiment(RecordSentimentEnum.RecordSentiment.forNumber(data.getSentiment()));
        }
        if (StringUtils.isNotBlank(data.getFieldId())) {
            builder.setFieldId(data.getFieldId());
        }
        if (StringUtils.isNotBlank(data.getFieldName())) {
            builder.setFieldName(data.getFieldName());
        }
        if (Objects.nonNull(data.getTime())) {
            builder.setTime(DateUtil.getTimestamp(data.getTime()));
        }
        if (StringUtils.isNotBlank(data.getIndustryId())) {
            builder.setIndustryId(data.getIndustryId());
        }
        if (Objects.nonNull(data.getFlag())) {
            builder.setFlag(RecordStatusEnum.RecordStatus.forNumber(data.getFlag()));
        }
        if (StringUtils.isNotBlank(data.getSurveyId())) {
            builder.setSurveyId(data.getSurveyId());
        }
        if (StringUtils.isNotBlank(data.getTopicInfo())) {
            builder.setTopicInfo(data.getTopicInfo());
        }
        if (CollUtil.isNotEmpty(data.getViews())) {
            List<ViewInfo> viewInfos = new ArrayList<>(DEFAULT_ARRAY_SIZE);
            for (int i = 0; i < data.getViews().size(); i++) {
                ViewInfoDTO viewInfoDTO = data.getViews().get(i);
                ViewInfo.Builder viewBuilder = ViewInfo.newBuilder();
                if (StringUtils.isNotBlank(viewInfoDTO.getId())) {
                    viewBuilder.setId(viewInfoDTO.getId());
                }
                if (Objects.nonNull(viewInfoDTO.getValues())) {
                    viewBuilder.setValues(viewInfoDTO.getValues());
                }
                if (StringUtils.isNotBlank(viewInfoDTO.getContent())) {
                    viewBuilder.setContent(viewInfoDTO.getContent());
                }
                if (StringUtils.isNotBlank(viewInfoDTO.getKey())) {
                    viewBuilder.setKey(viewInfoDTO.getKey());
                }
                viewInfos.add(viewBuilder.build());
            }
            if (CollUtil.isNotEmpty(viewInfos)) {
                builder.addAllViews(viewInfos);
            }
        }
        BaseModel.Builder baseModelBuilder = BaseModel.newBuilder();
        if (Objects.nonNull(data.getCreatedDate())) {
            baseModelBuilder.setCreateTime(DateUtil.getTimestamp(data.getCreatedDate()));
        }
        if (StringUtils.isNotBlank(data.getCreatedId())) {
            baseModelBuilder.setCreatedId(data.getCreatedId());
        }
        if (Objects.nonNull(data.getUpdatedDate())) {
            baseModelBuilder.setUpdateTime(DateUtil.getTimestamp(data.getUpdatedDate()));
        }
        if (StringUtils.isNotBlank(data.getUpdatedId())) {
            baseModelBuilder.setUpdatedId(data.getUpdatedId());
        }
        builder.setBaseModel(baseModelBuilder.build());
        return builder.build();
    }
}
